﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Web;
using Newtonsoft.Json;
using System.Collections.Specialized;

namespace CallCenter.Common
{

    /// <summary>
    /// Http操作类
    /// </summary>
    public class HttpHelper
    {
        private static readonly string DefaultUserAgent = $"Mozilla/5.0 (Windows NT 6.1; Win64; x64)" +
            $" AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36";

        /// <summary>
        /// 获取当前网页的内容
        /// </summary>
        /// <param name="httpUrl">Url地址</param>
        /// <param name="timeOut">请求响应超时时间，单位秒，默认30s</param>
        /// <param name="encoding">编码方式</param>
        /// <param name="userAgent">HTTP User-agent值</param>
        /// <param name="cookies">发送Cookie信息,常用于身份验证</param>
        /// <returns></returns>
        public static string HttpGet(string httpUrl, int timeOut = 30, Encoding encoding = null, string userAgent = "",
            CookieCollection cookies = null)
        {
            string result = "";

            try
            {
                encoding = encoding ?? Encoding.UTF8;
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(httpUrl);
                request.UserAgent = userAgent;
                request.Timeout = timeOut * 1000;
                //发送Cookie信息
                if (cookies != null)
                {
                    request.CookieContainer = new CookieContainer();
                    request.CookieContainer.Add(cookies);
                }

                // request.Headers.Add("Authorization", "004170-4E2D9BEAF85983B9E509602B8E8583B1");

                //获取响应内容
                using (WebResponse wr = request.GetResponse())
                {
                    //在这里对接收到的页面内容进行处理
                    using (StreamReader reader = new StreamReader(wr.GetResponseStream(), encoding))
                    {
                        result = reader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                JsonSerializerSettings setting = new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore
                };

                var exMessage = JsonConvert.SerializeObject(ex, setting);
                log4net.LogManager.GetLogger(typeof(HttpHelper)).Error(exMessage);
            }

            return result;
        }

        /// <summary>
        /// 获取当前网页的内容
        /// </summary>
        /// <param name="httpUrl">Url地址</param>
        /// <param name="timeOut">请求响应超时时间，单位秒，默认30s</param>
        /// <param name="encoding">编码方式</param>
        /// <param name="userAgent">HTTP User-agent值</param>
        /// <param name="cookies">发送Cookie信息,常用于身份验证</param>
        /// <returns></returns>
        public static string HttpGetWithAuthorization(string httpUrl, int timeOut = 30)
        {
            string result = "";
            try
            {
                Encoding encoding = Encoding.UTF8;

                HttpWebRequest request = WebRequest.Create(httpUrl) as HttpWebRequest;
                request.Timeout = timeOut * 1000;
                // request.Headers.Add("Authorization", posCode + "-" + Md5Utils.Sign(posCode, encoding));

                //获取响应内容
                using (WebResponse wr = request.GetResponse())
                {
                    //在这里对接收到的页面内容进行处理
                    using (StreamReader reader = new StreamReader(wr.GetResponseStream(), encoding))
                    {
                        result = reader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                log4net.LogManager.GetLogger(typeof(HttpHelper)).Error(
                    $"HttpHelper.GetUrlString,【Url地址】{httpUrl}：{ex.Message}");
            }

            return result;
        }

        /// <summary>
        /// 获取Post提交数据后返回的字符串
        /// </summary>
        /// <param name="httpUrl">Url地址</param>
        /// <param name="dataStr">Post数据</param>
        /// <param name="timeOut">请求响应超时时间，单位秒，默认30s</param>
        /// <param name="encoding">编码方式</param>
        /// <param name="userAgent">HTTP User-agent值</param>
        /// <param name="cookies">发送Cookie信息,常用于身份验证</param>
        /// <returns></returns>
        public static string HttpPost(string httpUrl, string dataStr, string token = "",
            int timeOut = 30, Encoding encoding = null,
            string userAgent = "", CookieCollection cookies = null)
        {
            string result = "";

            try
            {
                encoding = encoding ?? Encoding.UTF8;

                HttpWebRequest request = WebRequest.Create(httpUrl) as HttpWebRequest;
                request.Method = "POST";
                request.ContentType = "application/json"; // "application/x-www-form-urlencoded";
                request.UserAgent = userAgent;
                request.Timeout = timeOut * 1000;

                // 王志国 增加 头部鉴权参数
                if (!string.IsNullOrEmpty(token))
                {
                    request.Headers.Add("Authorization", token);
                }

                // 发送Cookie信息
                if (cookies != null)
                {
                    request.CookieContainer = new CookieContainer();
                    request.CookieContainer.Add(cookies);
                }

                // 发送提交内容
                byte[] data = encoding.GetBytes(dataStr);
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }

                // 获取响应内容
                using (WebResponse wr = request.GetResponse())
                {
                    // 在这里对接收到的页面内容进行处理
                    using (StreamReader reader = new StreamReader(wr.GetResponseStream(), encoding))
                    {
                        result = reader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                JsonSerializerSettings setting = new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore
                };

                var exMessage = JsonConvert.SerializeObject(ex, setting);

                log4net.LogManager.GetLogger(typeof(HttpHelper)).Error(exMessage);
            }

            return result;
        }

        /// <summary>
        /// Http Post form-data格式接口请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="stringDict"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public static string HttpPostForm(string url, NameValueCollection stringDict, string token = "")
        {
            System.Net.ServicePointManager.DefaultConnectionLimit = 200;
            string responseContent;
            var memStream = new MemoryStream();
            var webRequest = (HttpWebRequest)WebRequest.Create(url);
            // 边界符
            var boundary = "----" + DateTime.Now.Ticks.ToString("x");    // "---------------"
            // 边界符
            var beginBoundary = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
            // 最后的结束符
            var endBoundary = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");

            // 设置属性
            webRequest.Method = "POST";
            webRequest.Timeout = 100000;  //最大设置100秒
            webRequest.KeepAlive = false;
            webRequest.UseDefaultCredentials = true;
            webRequest.ServicePoint.Expect100Continue = false;
            webRequest.ContentType = "multipart/form-data; boundary=" + boundary;

            // 王志国 增加 头部鉴权参数
            if (!string.IsNullOrEmpty(token))
            {
                webRequest.Headers.Add("Authorization", token);
            }

            // 写入字符串的Key
            var stringKeyHeader = "\r\n--" + boundary +
                                   "\r\nContent-Disposition: form-data; name=\"{0}\"" +
                                   "\r\n\r\n{1}";

            foreach (byte[] formitembytes in from string key in stringDict.Keys
                                             select string.Format(stringKeyHeader, key, stringDict[key])
                                             into formitem
                                             select Encoding.UTF8.GetBytes(formitem))
            {
                memStream.Write(formitembytes, 0, formitembytes.Length);
            }

            // 写入最后的结束边界符
            memStream.Write(endBoundary, 0, endBoundary.Length);
            webRequest.ContentLength = memStream.Length;
            var requestStream = webRequest.GetRequestStream();
            memStream.Position = 0;
            var tempBuffer = new byte[memStream.Length];
            memStream.Read(tempBuffer, 0, tempBuffer.Length);
            memStream.Close();

            requestStream.Write(tempBuffer, 0, tempBuffer.Length);
            requestStream.Close();

            var httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
            using (var httpStreamReader = new StreamReader(httpWebResponse.GetResponseStream(), Encoding.GetEncoding("utf-8")))
            {
                responseContent = httpStreamReader.ReadToEnd();
            }

            httpWebResponse.Close();
            webRequest.Abort();
            return responseContent;
        }

        /// <summary>
        /// 下载指定文件的字节流
        /// </summary>
        /// <param name="httpUrl">下载文件的地址</param>
        /// <param name="timeOut">下载文件超时时间，单位秒，默认60s</param>
        /// <param name="userAgent">HTTP User-agent值</param>
        /// <param name="cookies">发送Cookie信息,常用于身份验证</param>
        /// <returns></returns>
        public static Byte[] GetUrlByte(string httpUrl, int timeOut = 60, string userAgent = "",
            CookieCollection cookies = null)
        {
            try
            {
                HttpWebRequest request = WebRequest.Create(httpUrl) as HttpWebRequest;
                request.UserAgent = userAgent;
                request.Timeout = timeOut * 1000;
                //发送Cookie信息
                if (cookies != null)
                {
                    request.CookieContainer = new CookieContainer();
                    request.CookieContainer.Add(cookies);
                }
                //获取响应内容流
                using (WebResponse wr = request.GetResponse())
                {
                    using (Stream reader = wr.GetResponseStream())
                    {
                        return reader.ToByte();
                    }
                }
            }
            catch (Exception ex)
            {
                JsonSerializerSettings setting = new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore
                };

                var exMessage = JsonConvert.SerializeObject(ex, setting);
                log4net.LogManager.GetLogger(typeof(HttpHelper)).Error($"httpUrl:{httpUrl}  Exception: {exMessage}");
            }

            return null;
        }

        /// <summary>
        /// 使用Post方法获取字符串结果
        /// </summary>
        /// <param name="url">接口访问地址</param>
        /// <param name="formItems">Post表单内容</param>
        /// <param name="token"> 请求 token </param>
        /// <param name="refererUrl"></param>
        /// <param name="cookieContainer"></param>
        /// <param name="timeOut">默认20秒</param>
        /// <param name="encoding">响应内容的编码类型（默认utf-8）</param>
        /// <returns></returns>
        public static string PostForm(string url, List<FormItemModel> formItems, string token = "",
            CookieContainer cookieContainer = null, bool isHttps = false,
            string refererUrl = null, Encoding encoding = null, int timeOut = 20000)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            #region 初始化请求对象

            request.Method = "POST";
            request.Timeout = timeOut;
            request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
            request.KeepAlive = true;
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36";

            // 王志国 增加 头部鉴权参数
            if (!string.IsNullOrEmpty(token))
            {
                request.Headers.Add("Authorization", token);
            }

            if (!string.IsNullOrEmpty(refererUrl))
            {
                request.Referer = refererUrl;
            }

            if (cookieContainer != null)
            {
                request.CookieContainer = cookieContainer;
            }

            #endregion

            string boundary = "----" + DateTime.Now.Ticks.ToString("x");       // 分隔符
            request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);

            if (isHttps)
            {
                // https形式需要添加
                ServicePointManager.ServerCertificateValidationCallback =
                    new RemoteCertificateValidationCallback(CheckValidationResult);
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
                request.ProtocolVersion = HttpVersion.Version11;
            }

            // 请求流
            var postStream = new MemoryStream();

            #region 处理Form表单请求内容

            //是否用Form上传文件
            var formUploadFile = formItems != null && formItems.Count > 0;
            if (formUploadFile)
            {
                //文件数据模板
                string fileFormdataTemplate =
                    "\r\n--" + boundary +
                    "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" +
                    "\r\nContent-Type: application/octet-stream" +
                    "\r\n\r\n";

                //文本数据模板
                string dataFormdataTemplate =
                    "\r\n--" + boundary +
                    "\r\nContent-Disposition: form-data; name=\"{0}\"" +
                    "\r\n\r\n{1}";

                foreach (var item in formItems)
                {
                    string formdata = null;
                    if (!string.IsNullOrEmpty(item.FileName))
                    {
                        int idx = item.FileName.LastIndexOf(@"\");
                        if (idx > 0)
                        {
                            item.UploadFileName = item.FileName.Substring(idx + 1);
                        }
                    }

                    if (item.IsFile)
                    {
                        //上传文件
                        formdata = string.Format(
                            fileFormdataTemplate,
                            item.Key, //表单键
                            item.UploadFileName);
                    }
                    else
                    {
                        //上传文本
                        formdata = string.Format(
                            dataFormdataTemplate,
                            item.Key,
                            item.Value);
                    }

                    //统一处理
                    byte[] formdataBytes = null;

                    //第一行不需要换行
                    if (postStream.Length == 0)
                    {
                        formdataBytes = Encoding.UTF8.GetBytes(formdata.Substring(2, formdata.Length - 2));
                    }
                    else
                    {
                        formdataBytes = Encoding.UTF8.GetBytes(formdata);
                    }

                    postStream.Write(formdataBytes, 0, formdataBytes.Length);

                    //写入文件内容
                    if (item.FileContent != null && item.FileContent.Length > 0)
                    {
                        using (var stream = item.FileContent)
                        {
                            byte[] buffer = new byte[1024];
                            int bytesRead = 0;
                            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
                            {
                                postStream.Write(buffer, 0, bytesRead);
                            }
                        }
                    }
                }

                // 结尾
                var footer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
                postStream.Write(footer, 0, footer.Length);

            }
            else
            {
                request.ContentType = "application/x-www-form-urlencoded";
            }

            #endregion

            request.ContentLength = postStream.Length;

            #region 输入二进制流

            if (postStream != null)
            {
                postStream.Position = 0;
                //直接写入流
                Stream requestStream = request.GetRequestStream();

                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    requestStream.Write(buffer, 0, bytesRead);
                }

                ////debug
                //postStream.Seek(0, SeekOrigin.Begin);
                //StreamReader sr = new StreamReader(postStream);
                //var postStr = sr.ReadToEnd();
                postStream.Close();     // 关闭文件访问
            }

            #endregion

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            if (cookieContainer != null)
            {
                response.Cookies = cookieContainer.GetCookies(response.ResponseUri);
            }

            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader myStreamReader = new StreamReader(responseStream, encoding ?? Encoding.UTF8))
                {
                    string retString = myStreamReader.ReadToEnd();
                    return retString;
                }
            }
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate,
            X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受   
        }

        /// <summary>
        /// Https Post 方法
        /// </summary>
        /// <param name="url"></param>
        /// <param name="headers"></param>
        /// <param name="parameters"></param>
        /// <param name="charset"></param>
        /// <returns></returns>
        public static string PostHttps(string url, string headers, IDictionary<string, string> parameters, Encoding charset)
        {
            HttpWebRequest request = null;
            CookieContainer cookie = new CookieContainer();

            //HTTPS  Q请求
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            request = WebRequest.Create(url) as HttpWebRequest;
            request.CookieContainer = cookie;
            request.ProtocolVersion = HttpVersion.Version11;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.UserAgent = DefaultUserAgent;
            request.KeepAlive = true;
            request.Headers["Accept-Language"] = "zh-CN,zh;q=0.9";
            request.Headers["token"] = headers;
            //request.Headers["Cookie"] = "username=aaaaaa; Language=zh_CN";

            //如果需要 POST 数据   
            if (!(parameters == null || parameters.Count == 0))
            {
                StringBuilder buffer = new StringBuilder();
                int i = 0;
                foreach (string key in parameters.Keys)
                {
                    if (i > 0)
                    {
                        buffer.AppendFormat("&{0}={1}", key, WebUtility.HtmlEncode(parameters[key]));
                    }
                    else
                    {
                        buffer.AppendFormat("{0}={1}", key, WebUtility.HtmlEncode(parameters[key]));
                    }

                    i++;
                }

                byte[] data = charset.GetBytes(buffer.ToString());
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
            }

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader myStreamReader = new StreamReader(responseStream, charset ?? Encoding.UTF8))
                {
                    string retString = myStreamReader.ReadToEnd();
                    return retString;
                }
            }
        }

        #region 已删除
        /*
        public static string PostFile(string getUrl, CookieContainer cookieContainer, HttpHeader header,
            string postdata, byte[] postdatabyte, Stream sm)
        {
            Stream fileStream = null;
            if (sm != null)
            {
                fileStream = sm;
            }
            else
            {
                fileStream = new MemoryStream(postdatabyte);
            }

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls;    //https形式需要添加
            string resultString = null;
            fileStream.Position = 0;
            var r = new BinaryReader(fileStream);
            string strBoundary = "--" + DateTime.Now.Ticks.ToString("x");
            byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + strBoundary + "--\r\n");
            //请求头部信息
            StringBuilder sb = new StringBuilder();
            sb.Append("--");
            sb.Append(strBoundary);
            sb.Append("\r\n");
            sb.Append("Content-Disposition: form-data; name=\"importType\"");
            sb.Append("\r\n\r\n1");
            sb.Append("\r\n");
            sb.Append("--");
            sb.Append(strBoundary);
            sb.Append("\r\n");
            sb.Append("Content-Disposition: form-data; name=\"file\"; filename=\"1.xls\"");
            sb.Append("\r\n");
            sb.Append("Content-Type: ");
            sb.Append("application/octet-stream");
            sb.Append("\r\n\r\n");
            string strPostHeader = sb.ToString();
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(strPostHeader);
            try
            {
                // 根据uri创建HttpWebRequest对象
                HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(getUrl));
                httpReq.Method = "POST";
                //对发送的数据不使用缓存
                httpReq.AllowWriteStreamBuffering = false;
                //设置获得响应的超时时间（300秒）
                httpReq.Timeout = 300000;
                //httpReq.ServicePoint.Expect100Continue = false;
                httpReq.CookieContainer = cookieContainer;
                httpReq.Accept = header.accept;
                //httpReq.Headers.Add("Accept-Encoding","gzip, deflate, br");
                //httpReq.Headers.Add("TE", "Trailers");
                httpReq.UserAgent = header.userAgent;
                httpReq.ContentType = "multipart/form-data; boundary=" + strBoundary;
                long length = fileStream.Length + postHeaderBytes.Length + boundaryBytes.Length;
                long fileLength = fileStream.Length;
                httpReq.ContentLength = length;
                byte[] buffer = new byte[fileLength];
                Stream postStream = httpReq.GetRequestStream();
                //发送请求头部消息
                postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
                int size = r.Read(buffer, 0, buffer.Length);
                postStream.Write(buffer, 0, size);
                //添加尾部的时间戳
                postStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                postStream.Close();
                //获取服务器端的响应
                HttpWebResponse webRespon = (HttpWebResponse)httpReq.GetResponse();
                if (webRespon.StatusCode == HttpStatusCode.OK) //如果服务器未响应，那么继续等待相应                 
                {
                    Stream s = webRespon.GetResponseStream();
                    StreamReader sr = new StreamReader(s);
                    //读取服务器端返回的消息
                    resultString = sr.ReadToEnd();
                    s.Close();
                    sr.Close();
                    fileStream.Close();
                }
            }
            catch (Exception ex)
            {
                NLogger.GetInstance().Error($"上传文件异常{ex.Message}\n{ex.StackTrace}");
            }

            return resultString;
        }
        */
        #endregion

        /// <summary>
        /// Https Post 使用Json上传数据的方法
        /// </summary>
        /// <param name="url"></param>
        /// <param name="headers"></param>
        /// <param name="jsonParams"></param>
        /// <returns></returns>
        public static string PostJsonByHttps(string url, string headers, string jsonParams)
        {
            HttpWebRequest request = null;
            CookieContainer cookie = new CookieContainer();

            //HTTPSQ请求
            ServicePointManager.ServerCertificateValidationCallback =
                new RemoteCertificateValidationCallback(CheckValidationResult);
            request = WebRequest.Create(url) as HttpWebRequest;
            request.CookieContainer = cookie;
            request.ProtocolVersion = HttpVersion.Version11;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.UserAgent = DefaultUserAgent;
            request.KeepAlive = true;
            request.Headers["Accept-Language"] = "zh-CN,zh;q=0.9";
            request.Headers["token"] = headers;
            //request.Headers["Cookie"] = "username=aaaaaa; Language=zh_CN";

            //如果需要POST数据   
            request.ContentType = "application/json;charset=UTF-8";
            byte[] byteData = Encoding.UTF8.GetBytes(jsonParams);
            int length = byteData.Length;
            request.ContentLength = length;

            using (Stream stream = request.GetRequestStream())
            {
                stream.Write(byteData, 0, byteData.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();

            using (StreamReader st = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
            {
                return st.ReadToEnd().ToString();
            }
        }
    }

    /// <summary>
    /// 表单数据项
    /// </summary>
    public class FormItemModel
    {
        /// <summary>
        /// 表单键，request["key"]
        /// </summary>
        public string Key { set; get; }

        /// <summary>
        /// 表单值,上传文件时忽略，request["key"].value
        /// </summary>
        public string Value { set; get; }

        /// <summary>
        /// 是否是文件
        /// </summary>
        public bool IsFile
        {
            get
            {
                if (FileContent == null || FileContent.Length == 0)
                    return false;

                if (FileContent != null && FileContent.Length > 0 && string.IsNullOrWhiteSpace(FileName))
                    throw new Exception("上传文件时 FileName 属性值不能为空");
                return true;
            }
        }

        /// <summary>
        /// 上传的文件名
        /// </summary>
        public string FileName { set; get; }

        /// <summary>
        /// 上传的文件名（不带路径）
        /// </summary>
        public string UploadFileName { get; set; }

        /// <summary>
        /// 上传的文件内容
        /// </summary>
        public Stream FileContent { set; get; }
    }
}
